﻿using AutoMapper;
using Newtonsoft.Json;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.LogDomain;
using Zocono.WCS.Domain.PlcBytesObject;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Infrastructure.ApllicationDto.Enums;
using Zocono.WCS.Infrastructure.ApllicationDto.WCSTaskDto;
using Zocono.WCS.Infrastructure.PlcCommon;
using Zocono.WCS.WMSApiDomain.WebApi;

namespace Zocono.WCS.Domain.EquipmentProcessDomain.PlanarGeneralMessage
{
    /// <summary>
    /// 到达上料台（PU）业务
    /// </summary>
    public class ArrivePuService : IPlanarGeneralPlcActionProcessService
    {
        private readonly IRedisHelper _IRedisHelper;
        private readonly ILogUtil _LogUtil;
        private readonly ISnowflake _Snowflake;
        private readonly IPlcConnectionPool _PlcConnectionPool;
        private readonly IWorkTaskInfoRepository _WorkTaskInfoRepository;
        private readonly IRouteDetailInfoRepository _RouteDetailInfoRepository;
        private readonly IPlcWriteDbInfoRepository _PlcWriteDbInfoRepository;
        private readonly ITaskRouteDetailRecordInfoRepository _TaskRouteDetailRecordInfoRepository;
        private readonly IPlcConnectionStateInfoRepository _IPlcConnectionStateInfoRepository;
        private readonly IRunLogInfoService _IRunLogInfoService;

        public ArrivePuService(IRedisHelper iRedisHelper, ILogUtil logUtil
           , ISnowflake snowflake
           , IPlcConnectionPool plcConnectionPool
           , IWorkTaskInfoRepository workTaskInfoRepository
           , IRouteDetailInfoRepository routeDetailInfoRepository
           , IPlcWriteDbInfoRepository plcWriteDbInfoRepository
           , ITaskRouteDetailRecordInfoRepository taskRouteDetailRecordInfoRepository
            , IPlcConnectionStateInfoRepository plcConnectionStateInfoRepository
             , IRunLogInfoService runLogInfoService)
        {
            _IRedisHelper = iRedisHelper;
            _LogUtil = logUtil;
            _Snowflake = snowflake;
            _PlcConnectionPool = plcConnectionPool;
            _WorkTaskInfoRepository = workTaskInfoRepository;
            _RouteDetailInfoRepository = routeDetailInfoRepository;
            _PlcWriteDbInfoRepository = plcWriteDbInfoRepository;
            _TaskRouteDetailRecordInfoRepository = taskRouteDetailRecordInfoRepository;
            _IPlcConnectionStateInfoRepository = plcConnectionStateInfoRepository;
            _IRunLogInfoService = runLogInfoService;
        }
        public async Task ProcessActionMessageAsync(BytesObjectBase plcActionMessage, BytesObjectBase wcsActionMessage
            , EquipmentDbObject planarEquipmentDbObject/*, BytesObjectBase plcStateMassge*/)
        {

            /*
             * 处理逻辑
             * 1. 验证plc是否在线
             * 2. 验证设备是否报警
             * 3. 验证wcs任务,验证wcs当前任务节点是否执行中节点
             * 4. 存在，则组织报文，写入plc
             * 5. 写入plc是否成功，成功，插入子任务记录信息,更新任务表信息
             */
            var plcMessage = plcActionMessage as PlanarGeneralPlcActionBO;//Plc的动作报文
            var wcsMessage = wcsActionMessage as PlanarGeneralWcsActionBO;//Wcs的动作报文
                                                                          //var plcStateBo = plcStateMassge as PlcOnLineStateBO;//Plc在线离线报文 没有设备信息
            plcMessage.PalletBarcode= plcMessage.PalletBarcode.Trim();


            PlcConnectionS7 plcConnect = _PlcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID); ;//plc写入连接（不锁定）
            RunLogInfo runLogInfo = new RunLogInfo();
            runLogInfo.ContainerBarcode = plcMessage.PalletBarcode;
            runLogInfo.EquipmentCode = plcMessage.EquipmentCode;
            runLogInfo.RunType = "到达上料台";

            runLogInfo.RunLog = "任务开始：到达上料台（PU）业务";
            //1. 验证plc是否在线
            var plcIPStates = await _IPlcConnectionStateInfoRepository.GetFirstAsync(l=>l.PlcConnectionID==plcMessage.PlcConnectionID&&l.Connected==true);
            if (plcIPStates == null)
            {
                //runLogInfo.RunLog = $"离线：{plcConnect.IP}plc已离线";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"到达上料台业务：设备【{plcMessage.EquipmentCode}】离线：{plcConnect.IP}plc已离线");
                return;
            }

            //if (plcMessage.AlrmCode != 0)
            //{
            //    runLogInfo.RunLog = $"报警:报警代码：{plcMessage.AlrmCode}";
            //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //    return;
            //}

            var plcConn = _PlcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID);
            if (plcConn == null)
            {
                //runLogInfo.RunLog = $"获取PLC写入连接({plcMessage.PlcConnectionID})失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"到达上料台业务：设备【{plcMessage.EquipmentCode}】获取PLC写入连接({plcMessage.PlcConnectionID})失败");
                return;
            }

         


            //_WorkTaskInfoRepository.AsSugarClient().Aop.OnLogExecuting = (sql, data) =>
            //{
            //    var l = sql;
            //};
            //任务重复检测删除
            var expRepeat = Expressionable.Create<WorkTaskInfo>();

            //expRepeat.AndIF(plcMessage.TaskCode > 0, it => it.TaskCode == plcMessage.TaskCode);
            expRepeat.AndIF(true, it => it.PalletCode == plcMessage.PalletBarcode && it.TaskState == EnumTaskState.Executing);
            var workTaskInfoRepeat = await _WorkTaskInfoRepository.AsSugarClient().Queryable<WorkTaskInfo>().Where(expRepeat.ToExpression()).ToListAsync();
            if(workTaskInfoRepeat.Count > 1)
            {
                await _WorkTaskInfoRepository.DeleteAsync(workTaskInfoRepeat.First());
            }



            //4. 组织报文，写入plc
            var objectType = typeof(PlanarGeneralWriteWcsAction).Name;
            var writeConfig = await _PlcWriteDbInfoRepository.GetFirstAsync(s => s.EquipmentCode == plcMessage.EquipmentCode && s.ObjectType == objectType);
            if (writeConfig == null)
            {
                //runLogInfo.RunLog = $"获取PLC写入配置失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

                _LogUtil.Error($"到达上料台业务：获取PLC设备【{plcMessage.EquipmentCode}】写入配置失败！请检查读DB配置！");
                return;
            }

            //plc报文是什么握手类型则回什么握手类型
            PlanarGeneralWriteWcsAction writeBo = new PlanarGeneralWriteWcsAction(
                writeConfig.PlcConnectionId,
                writeConfig.ID,
                writeConfig.DbCode,
                writeConfig.DbStart,
                objectType,
                plcMessage.EquipmentCode.Trim().ToInt32(),
                0,
                0,
                0,//任务号
                plcMessage.PalletBarcode.Trim(),
                0,
                0);


            //校验plc信息是否有托盘码
            if (string.IsNullOrEmpty(plcMessage.PalletBarcode) || plcMessage.PalletBarcode.Length != 10)
            {
                writeBo.AlrmCode = 102;
                writeBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            //3. 验证wcs任务,验证wcs当前任务节点是否执行中节点
            var exp = Expressionable.Create<WorkTaskInfo>();

            //exp.AndIF(plcMessage.TaskCode > 0, it => it.TaskCode == plcMessage.TaskCode);
            exp.AndIF(true, it => it.PalletCode == plcMessage.PalletBarcode && it.TaskState == EnumTaskState.Executing);
            var workTaskInfo = await _WorkTaskInfoRepository.GetFirstAsync(exp.ToExpression());
           
            if (workTaskInfo == null)
            {
                //runLogInfo.RunLog = $"任务号({plcMessage.TaskCode})执行中的任务数据异常查找不到数据";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                //writeBo.ActionType = 0;
                //writeBo.AlrmCode = 7;
                //var write = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());

                _LogUtil.Error($"到达上料台业务：托盘码【{plcMessage.PalletBarcode}】任务号({plcMessage.TaskCode})执行中的任务数据异常查找不到数据");

                writeBo.AlrmCode = 114;
                writeBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }





            //托盘类型
            switch (plcMessage.PalletBarcode.Substring(1, 1))
            {
                case "A":
                    writeBo.PalletType = 2;
                    break;
                case "B":
                    writeBo.PalletType = 1;
                    break;
                case "C":
                    writeBo.PalletType = 3;
                    break;
            }
            //当前ID是正在执行路径的节点，PrevionsID是上一节点的ID
            var routeDetailInfo = await _RouteDetailInfoRepository.GetFirstAsync(s => s.PrevionsID == workTaskInfo.CurrentRounteDetailID);
            if (routeDetailInfo == null)
            {
                ////防止已经写PLC，但未收到任务已更新出错
                //if (workTaskInfo.CurrentDispatchType == EnumDispatchType.SC_UP)
                //{
                //    var write = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                //}
                //runLogInfo.RunLog = $"任务号({plcMessage.TaskCode})当前的任务路径明细节点为空";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"到达上料台业务：托盘码【{workTaskInfo.PalletCode}】任务号({workTaskInfo.TaskCode})当前的任务路径【{workTaskInfo.CurrentFromEquipment}->{workTaskInfo.CurrentToEquipment}】明细节点为空");
                writeBo.AlrmCode = 115;
                writeBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            ///防呆处理,当PLC当前设备号与执行任务当前的目标位置不一致，不允许交互
            if (!plcMessage.EquipmentCode.Equals(workTaskInfo.CurrentToEquipment))
            {
                //runLogInfo.RunLog = $"PLC当前设备号({plcMessage.EquipmentCode})与执行任务当前目标位置({workTaskInfo.CurrentToEquipment})不一致，托盘走错位置";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                //writeBo.ActionType = 0;
                //writeBo.AlrmCode = 53;
                //var write = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _LogUtil.Error($"到达上料台业务：托盘码【{workTaskInfo.PalletCode}】任务号【{workTaskInfo.TaskCode}】PLC当前设备号({plcMessage.EquipmentCode})与执行任务当前目标位置({workTaskInfo.CurrentToEquipment})不一致，托盘走错位置");
                writeBo.AlrmCode = 116;
                writeBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }
            //var writeResult = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
            //if (writeResult == false)
            //{
            //    _LogUtil.Info($"[到达PU]处理失败：PLC(IP{plcConn.IP},设备{writeBo.EquipmentCode})写入报文失败");

            //    return;
            //}

            //插入子任务记录信息
            TaskRouteDetailRecordInfo taskRouteDetailRecordInfo = new TaskRouteDetailRecordInfo();
            taskRouteDetailRecordInfo.ID = _Snowflake.GetId();
            taskRouteDetailRecordInfo.TaskID = workTaskInfo.ID;
            taskRouteDetailRecordInfo.RouteDetailID = workTaskInfo.CurrentRounteDetailID;
            taskRouteDetailRecordInfo.DetailTaskState = EnumDetailTaskState.Finish;
            taskRouteDetailRecordInfo.DispatchType = workTaskInfo.CurrentDispatchType;
            taskRouteDetailRecordInfo.FromEquipment = workTaskInfo.CurrentFromEquipment;
            taskRouteDetailRecordInfo.FromCargo = workTaskInfo.CurrentFromCargo;
            taskRouteDetailRecordInfo.ToEquipment = workTaskInfo.CurrentToEquipment;
            taskRouteDetailRecordInfo.ToCargo = workTaskInfo.CurrentToCargo;//?
            taskRouteDetailRecordInfo.CreateTime = workTaskInfo.CurrentCreateTime;
            taskRouteDetailRecordInfo.UpdateTime = workTaskInfo.CurrentUpdateTime;

            await _TaskRouteDetailRecordInfoRepository.InsertAsync(taskRouteDetailRecordInfo);

            //5.写入成功
            //申请货位分配 

            try
            {
                //int colum = !string.IsNullOrEmpty(routeDetailInfo.FromCargo) ? Convert.ToInt32(routeDetailInfo.FromCargo.Substring(4, 3)) : 1;
                if (routeDetailInfo.DispatchType == EnumDispatchType.SC_UP)
                {
                    AllotLocationOutputDto allotLocationOutputDto = null;
                    WMSApiDomain.WebApi.HeaderResult<AllotLocationOutputDto> res = await WCSMessageWithWMSApi.WCSGetAllotLocatonAsync(workTaskInfo.WmsTaskCode, plcMessage.EquipmentCode.Trim(),
                                plcMessage.PalletBarcode.Trim(), routeDetailInfo.FromCargoColumn);//向WMS获取货位信息
                    if (res.IsSucceed)
                    {
                        allotLocationOutputDto = res.Result;
                    }
                    else
                    {
                        var msg = res.Message;
                        runLogInfo.RunLog = $"向Wms请求货位失败:{msg}";
                        //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

                        if (msg.Contains("没有执行中的任务"))
                            writeBo.AlrmCode = 31;
                        else if (msg.Contains("绑定托盘条码与WCS传入托盘条码"))
                            writeBo.AlrmCode = 32;
                        else if (msg.Contains("没有路径配置数据"))
                            writeBo.AlrmCode = 33;
                        else if (msg.Contains("没有路径配置巷道数据"))
                            writeBo.AlrmCode = 34;
                        else if (msg.Contains("没有配置托盘数据"))
                            writeBo.AlrmCode = 35;
                        else if (msg.Contains("作业托盘号与参数托盘号不一致"))
                            writeBo.AlrmCode = 36;
                        else if (msg.Contains("作业托盘号不符合条码规则"))
                            writeBo.AlrmCode = 37;
                        else if (msg.Contains("作业托盘号绑定的订单不存在"))
                            writeBo.AlrmCode = 38;
                        else if (msg.Contains("法找到订单绑定的电池型号"))
                            writeBo.AlrmCode = 39;
                        else if (msg.Contains("查找的货位已无货位"))
                            writeBo.AlrmCode = 40;
                        else if (msg.Contains("爆仓流程没有配置货位"))
                            writeBo.AlrmCode = 45;
                        //else if (writeBo.AlrmCode == 0)
                        //    writeBo.AlrmCode = 8;
                        else
                            writeBo.AlrmCode = 117;
                        //writeBo.ActionType = 0;
                        //var writeBl = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                        _LogUtil.Error($"到达上料台业务：托盘码【{workTaskInfo.PalletCode}】入库台【{plcMessage.EquipmentCode}】向Wms请求货位失败:{msg}");
                        writeBo.ActionType = 99;
                        var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                        _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                        return;
                    }
                    //await WCSMessageWithWMSApi.WCSGetAllotLocatonAsync(workTaskInfo.WmsTaskCode, plcMessage.EquipmentCode, plcMessage.PalletBarcode.Trim(), routeDetailInfo.FromCargoColumn);//FromCargoColumn接驳台的列
                    //AllotLocationOutputDto allotLocationOutputDto = new AllotLocationOutputDto()
                    //{
                    //    LocationCode = "B00100200101"
                    //};

                    if (allotLocationOutputDto != null)
                        workTaskInfo.WmsToPosition = allotLocationOutputDto.LocationCode;
                    workTaskInfo.CurrentToCargo = routeDetailInfo.ToCargo == "ToCargo" ? allotLocationOutputDto.LocationCode : routeDetailInfo.ToCargo;

                }
                else if (routeDetailInfo.DispatchType == EnumDispatchType.SC_CROSS)
                {
                    workTaskInfo.CurrentToCargo = routeDetailInfo.ToCargo;//= routeDetailInfo.ToCargo;//?????
                }

                workTaskInfo.CurrentRounteDetailID = routeDetailInfo.ID;
                workTaskInfo.CurrentDetailTaskState = EnumDetailTaskState.Init;
                workTaskInfo.CurrentDispatchType = routeDetailInfo.DispatchType;
                workTaskInfo.CurrentFromEquipment = routeDetailInfo.FromEquipment;
                workTaskInfo.CurrentFromCargo = routeDetailInfo.FromCargo;
                workTaskInfo.CurrentToEquipment = routeDetailInfo.ToEquipment;
                workTaskInfo.CurrentUpdateTime = DateTime.Now;
            }
            catch (Exception ex)
            {

                //writeBo.ActionType = 0;
                //writeBo.AlrmCode = 8;
                //var write = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                //if (ex.Message.Contains("at") && ex.Message.Contains("System.Exception:"))
                //{

                //    var msg = ex.Message.Split("at").First().Split("System.Exception:");
                //    runLogInfo.RunLog = $"申请货位异常:{msg[1]}";

                //}
                //else
                //{
                //    var msg = ex.Message.Length > 150 ? ex.Message[..100] : ex.Message;
                //    runLogInfo.RunLog = $"申请货位异常:{msg}";
                //}

                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"到达上料台业务：托盘码【{workTaskInfo.PalletCode}】入库台【{plcMessage.EquipmentCode}】申请货位异常:{ex.Message}");
                writeBo.AlrmCode = 118;
                writeBo.ActionType = 99;
                var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                return;
            }

            //前面都通过，则任务开始
            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            //runLogInfo.RunLog = $"PLC写入报文内容： {JsonConvert.SerializeObject(writeBo)}";
            //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
            writeBo.TaskCode = workTaskInfo.TaskCode;
            writeBo.ToEquipmentCode = workTaskInfo.CurrentToEquipment.Substring(2).ToInt32();
            //处理完成握手类型plc给什么回什么
            writeBo.ActionType = plcMessage.ActionType;
            var writeResult = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
            //LogWriter.WritePuPlanerLog(plcActionMessage.EquipmentCode, "PLC报文：" + JsonConvert.SerializeObject(plcMessage) + Environment.NewLine + "WCS报文：" + JsonConvert.SerializeObject(writeBo));
            if (writeResult == false)
            {
                //runLogInfo.RunLog = $"到达上料台业务：托盘码【{workTaskInfo.PalletCode}】入库台【{plcMessage.EquipmentCode}】PLC(IP{plcConn.IP},写入报文失败";
                //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                _LogUtil.Error($"到达上料台业务：托盘码【{workTaskInfo.PalletCode}】入库台【{plcMessage.EquipmentCode}】PLC(IP{plcConn.IP},写入报文失败");
                return;
            }
            runLogInfo.RunLog = $"到达上料台业务：托盘码【{workTaskInfo.PalletCode}】入库台【{plcMessage.EquipmentCode}】PLC写入成功！报文内容： {JsonConvert.SerializeObject(writeBo)}";
            await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);

            //更新当前子任务
            await _WorkTaskInfoRepository.UpdateAsync(workTaskInfo);

            runLogInfo.RunLog = $"到达上料台业务：托盘码【{workTaskInfo.PalletCode}】入库台【{plcMessage.EquipmentCode}】[到达PU]处理成功";
            await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
        }
    }
}
